package reflect2;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/*
    使用Class类对象中的功能：(前提是现获取当前类的Class对象)
        获取功能：1.获取类中的成员变量们
                   Field[]  getFields() 返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的 public 权限的成员变量
                   Field getField(String name) 返回一个 Field对象，它反映此表示的类或接口 指定的public 权限的成员变量

                   Field[] getDeclaredFields() 返回的数组 Field对象反映此表示的类或接口声明的 所有修饰权限 的成员变量
                   Field getDeclaredField(String name) 返回一个 Field对象，它反映此表示的类或接口 指定的所有修饰权限的成员变量

                 2.获取构造方法们：
                    Constructor<?>[]  getConstructors() 返回包含一个数组 Constructor对象反射由此表示的类的所有  公共构造 类对象
                    Constructor<T> getConstructor(类<?>... parameterTypes) 返回一个 Constructor对象，该对象反映 Constructor对象表示的类的指定的公共 类函数

                    Constructor<?>[]  getDeclaredConstructors() 返回一个反映 Constructor对象表示的类声明的 所有Constructor对象的数组 类
                    Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) 返回一个 Constructor对象，该对象反映 Constructor对象表示的类或接口的指定 类函数

                 3.获取成员方法们：
                    Method[] getMethods() 返回包含一个数组 方法对象反射由此表示的类或接口的 所有公共方法 类对象，包括那些由类或接口和那些从超类和超接口继承的声明。
                    Method getMethod(String name, 类<?>... parameterTypes) 返回一个 方法对象，它反映此表示的类或接口的指定公共成员方法 类对象。

                    Method[] getDeclaredMethods() 返回包含一个数组 方法对象反射的类或接口的所有声明的方法，通过此表示 类对象，包括公共，保护，默认（包）访问和私有方法，但不包括继承的方法
                    Method getDeclaredMethod(String name, 类<?>... parameterTypes) 返回一个 方法对象，它反映此表示的类或接口的指定声明的方法 类对象。

                 4.获取类名：
                    String  getName()


       获取到成员变量可进行的操作：（需要先创建对象）
            设置值：void set(Object obj, Object value) 将指定对象参数上的此Field对象表示的字段设置为指定的新值。
            获取值：Object  get(Object obj) 返回该所表示的字段的值，返回类型Object
            3.忽略访问权限的安全检查;
                    setAccessible(true)：暴力反射

       获取到构造方法可进行的操作：
           1. 创建对象：T newInstance(Object... initargs) 使用此 Constructor对象表示的构造函数，使用指定的初始化参数来创建和初始化构造函数的声明类的新实例
           2.如果创建空参对象是可以简化代码的：newInstance(),不推荐使用
           3.忽略访问权限的安全检查;
                    setAccessible(true)：暴力反射

       获取到成员方法可进行的操作：
           1.执行成员方法：Object invoke(Object obj, Object... args) 在具有指定参数的方法对象上调用此方法对象表示的底层方法(前提是先创建对应类的对新象)
           2.忽略访问权限的安全检查;
                    setAccessible(true)：暴力反射
           3.获取方法名称：String  getName()

 */
public class PracticeMain {
    public static void main(String[] args) throws Exception {
        //获取当前类的Class对象
        Class dogClass = Dog.class;

        //1.获取类中的成员方法们
        //getFields()
        Field[] fields = dogClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("========================================");

        //getField(String name)
        Field a = dogClass.getField("a");//会抛出异常
        //获取成员变量a的值，前提是需要先创建成员变量所在的类的对象
        Dog dog = new Dog();
        Object value = a.get(dog); //从dog类中获取

        //设置a的值
        a.set(dog,"旺财");//给dog这个类中的成员变量a赋值
        System.out.println(dog);
        System.out.println("=========================================");

        //getDeclaredFields()
        Field[] ds = dogClass.getDeclaredFields();
        for (Field d : ds) {
            System.out.println(d);
        }

        // Field getDeclaredField(String name)
        Field gf = dogClass.getDeclaredField("d");
        /*
            注意：在访问私有的或者是有安全检查的修饰权限时，需要进行忽略访问权限的安全检查，就可以进行使用了
                    称为：暴力反射 setAccessible(true)
         */
        gf.setAccessible(true);
        Object o = gf.get(dog);//从dog类中获取d成员变量
        System.out.println(o);

        System.out.println("----------------------------------------------------------------");

        //2.获取构造方法们：
        // Constructor<T> getConstructor(类<?>... parameterTypes)
        Constructor constructor = dogClass.getConstructor(String.class,int.class);//根据传递的参数来获取对应的构造方法
        System.out.println(constructor);
        //用构造器来创建对象
        //注意：不同的class类对象要写在不同的类中，不要写在同一个类中，否则会出现对象创建错误
        Object dog2 = constructor.newInstance( "小狗",3);//传入具体参数
        System.out.println(dog2);

//         Class catClass = Cat.class;
//        //2.获取构造方法们：
//        // Constructor<T> getConstructor(类<?>... parameterTypes)
//        Constructor constructor = catClass.getConstructor(int.class,String.class);//根据传递的参数来获取对应的构造方法
//        System.out.println(constructor);
//        //用构造器来创建对象
//        //注意：不同的class类对象要写在不同的类中，不要写在同一个类中，否则会出现对象创建错误
//        Object cat = constructor.newInstance(3, "小猫");//传入具体参数
//        System.out.println(cat);

        //空参构造器
        Constructor constructor1 = dogClass.getConstructor();
        System.out.println(constructor1);
        //使用构造器创建对象
        Object dog3 = constructor1.newInstance();
        System.out.println(dog3);

        //创建空参对象是可以简化代码(不推荐)
        Object dog4 = dogClass.newInstance();
        System.out.println(dog4);
        System.out.println("------------------------------------------------------");

        //3.获取成员方法们：
        //Method getMethod(String name, 类<?>... parameterTypes)
        //获取无参成员方法
        Method myDog = dogClass.getMethod("myDog");//需要传递方法名和方法的参数来确定所要获取法
        //前提是先创建对应类的对新象
        Dog dog1 = new Dog();
        //执行成员方法
        myDog.invoke(dog1);//传入方法所在的对象

        //获取有参成员方法
        Method myDog2 = dogClass.getMethod("myDog2", String.class);//需要传递方法名和方法的参数来确定所要获取的方法
        //执行成员方法
        myDog2.invoke(dog1,"香肠");//传入实参

        // Method[] getMethods()
        //注意：获取的类会继承Object类，所以获取的方法会包含父类的方法
        Method[] methods = dogClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            //获取方法名称
            String name = method.getName();
            System.out.println(name);
        }

        //4.获取类名:
        //String  getName()
        String name = dogClass.getName();
        System.out.println(name);

    }
}
